
/* ---------------------------------------
This sketch reads a linear encoder. It uses both interupts on the arduino.
poutputs one bargraph, voltage output on PWM pin 11, serial communications to LCD via the hardware serial. 
I used a simple r=100k and c=1 uF in a lowpass filter with a simple op-amp voltage follower and it seems to work.

trying to make this into a unit with 4 CV outputs, hence some variable names go that way.
Expanded to four output pins. uses a control register for each of the four channels of output to control what gets written where.
this will service two encoders eventually, requireing four interrupts.
------------------------------------------
to do
1) offset function for expression mode switches 0 and 2
2) multiple waveforms
3) lights on pedalboard?
4) fix BPM meter

Pay attention to disabling interrupt during the SPI transfer, as the waveform generator is asynchronous to the rest of the loop, will crash!

imported BPM code in ver 7 worked out relationship between BPM data and waveform period in version 9... 
divided samples (2^16) by 15 then used shift right twice to convert BPM's to Hz for the lookup table (devide by 60), works better for LFO 
may want to add option to mult by 2 or 4 (and triplet 3) 

have BPM control waveform as a user option, or use pedal positions for freq / amplitude  / offset of waveform generator >>>> limits are 8 to about 1750 BPM

1) Four bar graphs correspond to the Vout Array

2) Implemented a state machine design using function pointers for the 4 control voltage outputs Vout1 to Vout4 that would 
assign the pedals to the output with the desired ramp, etc.

3) update the functArr, on interrupt frequency - one channel per loop to keep the ISR time shorter, cannot put midi in the ISR, too slow

4) probably want to turn off LED's after a few seconds following switch press, could depend on function

5) USER INTERFACE done, maybe preset save / restore one day... 

6)  digital pots used  because it is be easy to set the min and max voltages by stringing three pots together and varying
the middle one by pedal position or waveform from generator

       |                 |  5 volts
       |                 |
       /                 / 
       \ <---|           \
       /     /           /
       \     \           \ 
        /    /           /
        |    \__________>\
        |                 |
        |                 |  Ground

>>> use the functArr to send Vout for display purposes, and send SPI data to digital pots

7) digital pots:  #define SLAVESELECTA 53//ss for A device, #define SLAVESELECTB 48//ss for B device  

wiring to 20 pin ribbon cable 

took out right nd left encoders on ribbon cable, seemed to prone to noise

      arduino pin                     19    18     20      21     16                  11*
                       5v     GND    ENCOD LEFT    ENCOD RIGHT   LCD    N.C.   N.C.    1
       (red stripe)    1|      |      |      |      |      |      |      |      |      |
                                             ribbon connector
                        |      |      |      |      |      |      |      |      |      |
                       11     10      9      8      7      6      5      4      3      2  <-- ART switch and LED matrix cable
      arduino pin      0      1       2      3      4**    5**    6**    8*     9*     10*           
                                                 **current lim 100ohm    *connect 1 k pullup
                                                                       
switch positions on pedalboard:
1  5  13  12  8  4  0
3  7  15  14  10  6  2
Note: there is no LED for 1,3,9,11 B00001111 turns off LED's - no switch in position 9, 11


Vout array set up with Mid scale to start,  256 resolution on PWM output (256 is full scale output) , 
MIDI register is half that (original ART function) so divide  by 2
*/

#include <avr/interrupt.h>
#include <EEPROM.h>

//encoder pinouts
#define encoder0PinA  21            //Quadrature Track A encoder0
#define encoder0PinB  20            //Quadrature Track B encoder0
#define encoder1PinA  19            //Quadrature Track A encoder1
#define encoder1PinB  18            //Quadrature Track B encoder1

//#define UNKNOWN 0
//#define EXP 1
//#define LFO 2
//#define MIDI_SYNC 3

//#define R_PED 0
//#define R_PED_INV 1
//#define L_PED 2
//#define L_PED_INV 3
//#define W_OUT 4
//#define HOLD_C 5

//#define SQU 0
//#define TRI 1
//#define SIN 2
//#define SIN1 3
//#define RAMP 4
//#define SAW 5

#define PRESET_SIZE 28
#define CHAN_PRESET_SIZE 7
#define NUM_PRESETS 10
#define NUM_CHANNELS 4
#define PRESET_OFFSET 32
#define CURRENT_PRESET_ADDRESS 8

//SPI pinouts
#define DATAOUT 51//MOSI
#define DATAIN 50//MISO - not used, but part of builtin SPI
#define SPICLOCK  52//sck
#define SLAVESELECTA 53//ss for A device
#define SLAVESELECTB 48//ss for B device  

//setup for tap tempo functions
#define A_SW 3 //slow switch input pin
#define B_SW 2 //fast switchinput pin
#define tapLED 4  // tap tempo LED output pin 
#include "WProgram.h"
unsigned char SetupTimer2(float timeoutFrequency);
void setup(void);
void loop();
int memoryTest();
void Set_Functions(byte chan, byte line);
void Set_And_Restore(byte chan, byte line);
void Lock_Functions(byte chan);
void Restore_Functions(byte chan , byte line);
void Set_Upper_Offset_A(byte chan, byte line);
void Set_Upper_Offset_B(byte chan, byte line);
void Set_Lower_Offset_A(byte chan, byte line);
void Set_Lower_Offset_B(byte chan, byte line);
void Offset_Adjust();
void RIGHT_PED(int channel);
void RIGHT_PED_INV(int channel);
void LEFT_PED(int channel);
void LEFT_PED_INV(int channel);
void RIGHT_PED_UPPER_OFFSET(int channel);
void LEFT_PED_UPPER_OFFSET(int channel);
void RIGHT_PED_LOWER_OFFSET(int channel);
void LEFT_PED_LOWER_OFFSET(int channel);
void HOLD_CHAN(int channel);
void WAVEOUT(int channel);
void flash_LED(byte lednum);
void blink_LED(byte lednum);
void BARGRAPH(byte chan);
void bar_fwd ();
void bar_back ();
byte write_pot_a(int address, int value);
byte write_pot_b(int address, int value);
char spi_transfer(volatile char data);
void tap();
void rescheduleTimer();
void slowerTap();
void fasterTap();
void disp_BPM();
void disp_TAP();
void MIDIcntrl(int cmd, int cntrl, int value);
void doEncoder0A();
void doEncoder0B();
void doEncoder1A();
void doEncoder1B();
int tapDelta = 0;
int BPM = 60;

//wavetable stuff
#define wave_led_pin 6      //waveform generator LED output pin

//midi timing function variables for midi in / out
boolean start_flag = false;    //synch the LFO, send out start message
boolean midi_clock_flag = false;  //user has selected midi clock output

byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;
int play_flag = 0;     //used for midi clock input - valid clock input state
byte data;

// set up functions: add to this list as functions are developed!

void (*functArr[4])(int);        //function pointer assignable to each channel
void (*PREV_functArr[4])(int);
void LEFT_PED(void);
void LEFT_PED_INV(void);
void RIGHT_PED(void);
void RIGHT_PED_INV(void);
void HOLD_CHAN(void);
void WAVEOUT(void);
void LEFT_PED_LOWER_OFFSET(void);
void RIGHT_PED_LOWER_OFFSET(void);
void LEFT_PED_UPPER_OFFSET(void);
void RIGHT_PED_UPPER_OFFSET(void);




//user modifiers for functions: add to this list as functions are developed!
int scale[4] = {NULL};
int topval[4] = {NULL};
int bottomval[4] = {NULL};
int old_topval[4] = {255, 255, 255, 255};
int old_bottomval[4] = {0, 0, 0, 0};

boolean top_offset[4] = {false, false, false, false};  //flag to pass to main loop to ipdate offsets
boolean bottom_offset[4] = {false, false, false, false};
boolean HI_LOW_OFFSET[4] = {false, false, false, false}; //mode for waveform generator if true, left and right pedals are the boundaries for the waveform
byte function[4] = {0, 0, 2, 2};  //function array for channels used for interface default is L, L, R, R 
boolean HOLD_FLAG[4] = {false, false, false, false};
boolean keypress = false; // used to toggle switches
unsigned long last_keypress = 0; // used to debounce keypad
boolean Set_Lower = false;        // logic to set lower offsets
boolean Save_Lower[4] = {false, false, false, false};
boolean Set_Upper = false;        // logic to set upper offsets 
boolean Save_Upper[4] = {false, false, false, false};
boolean offset_lockout = false;

// misc global system variables
int i = 0;           //counter
int switchin = 0;      //result of switch input read
int swnum = 1;      // switch number result
boolean light_led[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
boolean blink_led[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
boolean blink_disable = false;
boolean disp_bargraph = false;
//int currentPreset = 0;

// array "led" will sequentially light the LED's on the pedalboard
byte led[] = {B00011011, B00101011, B01001011, B01000111, B00100111, B00010111, B00011101, 
B00101101, B01001101, B01001110, B00101110, B00011110};

//array "switchled" correspponds to the swnum variable to turn on the corresponding LED to a switch activation
byte switchled[] = {B00011110, B00001111, B00011011, B00001111, B00101110, B00011101, B00101011, 
B00010111, B01001110, B00001111, B01001011, B00001111, B01001101, B00101101, B01000111, B00100111};

// array "strobe" cyles the LOW between the common 4 line matrix to read input switches
byte strobe[] = {B00001110, B00001101, B00001011, B00000111};

//define wavetable phase variables

byte *waveArr[4];  //pointer for wavetable lookup assigned to each channel
volatile unsigned int phase = 0;
volatile unsigned int phase_tab = 0;
volatile unsigned int phaseDelta = 0;
//byte Mult[4] = {8, 8, 8, 8};    // freq multiplier for wavetable to adjust for other note length values

// define the timer counter variables
unsigned int latency;
unsigned int latencySum;
unsigned int sampleCount;
unsigned char timerLoadValue;


//encoder variables
volatile int  encoder0Pos = 64;      //the encoder position variable RIGHT PEDAL
volatile int  encoder1Pos = 64;      //the encoder position variable LEFT PEDAL
volatile int  old_encoder0Pos[4] = {64, 64, 64, 64};      //the previous encoder position variable RIGHT PEDAL
volatile int  old_encoder1Pos[4] = {64, 64, 64, 64};      //the previous encoder position variable LEFT PEDAL
volatile int resistance = 0;          //lookuptable for wave gen
int potval = 0;

// variables for producing bar graph display need to change lables?
int N = 0;                           
int Num_5 = 0;
int cursor1 = 0;
int cursor2 = 0;
int cursor3 = 0;
int cursor4 = 0;
int I = 0;
boolean display_BPM = false;
byte curs[4] = {0,0,0,0};

//tap tempo stuff for loop
int lastslowState = LOW;
int lastfastState = LOW;
int slowState = LOW;
int fastState = LOW;

unsigned long currentTimer[2] = {500, 500};  /* array of most recent tap counts */
unsigned long timeoutTime = 0;  /* this is when the timer will trigger next */
unsigned long indicatorTimeout; /* for our fancy "blink" tempo indicator */

volatile boolean inhibit_LED = false; //turn off wavetable bllink while reading BPM on taps

////VoutXCR =   0 channel "off"    // the VoutCR thing needs to be reworked!
////            1 display BPM
////            2 display footpedal forward or reversed
////            3 Reversed output from Encoder 0
////            4 Output from Encoder 1
////            5 Reversed output from encoder 1
//
//byte VoutCR[4] = {2, 2, 2, 2};        //control registers to determine what device is setting voltage level *clean this up?
//                            //defaults to left encoder to 1 and 2: encoder 0
//                            //defaults to right encoder 3 and 4: encoder 1

int Vout[4] = {124, 124, 124, 124};        //Array output value for CV1 for PWM 256 resolution
int wave_channel[4] = {0, 0, 0, 0};              // this vector sets waveforms to the corresponding "1" in channel
int MIDIcc[4] = {16, 17, 18, 19};          //MIDI cc numbers 16-19 are general controllers may want user defined cc numbers
boolean MIDIVout[4] = {false, false, false, false};
byte zcount = 0;           //for switch matrix read

//Setup Timer2.
#define TIMER_CLOCK_FREQ 250000.0 //250kHz for 64 prescale from 16MHz for the timer2 interrupt had to use a slower clock to get a divide by 15 to work for BPM convert
//Configures the 8-Bit Timer2 to generate an interrupt at the specified frequency (timeout frequency)
//Returns the time load value which must be loaded into TCNT2 inside your ISR routine and will account for latency to keep this freq solid.

  unsigned char SetupTimer2(float timeoutFrequency){
  unsigned char result; //The value to load into the timer to control the timeout interval.

//  //Calculate the timer load value  ...larger the number, the sooner the interrupt fires... higher freq
  result=(int)((257.0-(TIMER_CLOCK_FREQ/timeoutFrequency))+0.5); //the 0.5 is for rounding;
  //The 257 really should be 256 but I get better results with 257, dont know why.
 TCCR2A = 0;
 TCCR2B |= (1<<CS22);    // turn on CS22 bit these two lines is  divide by 64 prescaler
 TCCR2B &= ~((1<<CS21) | (1<<CS20));    // turn off CS21 and CS20 bits
  //Timer2 Overflow Interrupt Enable   
 TIMSK2 = 1<<TOIE2;
  //load the timer for its first cycle
  TCNT2=result; 
  
 return(result);
}



byte SINE_TABLE[]=
{
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c,
};

byte SAW_TABLE[]=
{
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
};

byte SAW_REV_TABLE[]=
{
0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0,
0xef,0xee,0xed,0xec,0xeb,0xea,0xe9,0xe8,0xe7,0xe6,0xe5,0xe4,0xe3,0xe2,0xe1,0xe0,
0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xd9,0xd8,0xd7,0xd6,0xd5,0xd4,0xd3,0xd2,0xd1,0xd0,
0xcf,0xce,0xcd,0xcc,0xcb,0xca,0xc9,0xc8,0xc7,0xc6,0xc5,0xc4,0xc3,0xc2,0xc1,0xc0,
0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0,
0xaf,0xae,0xad,0xac,0xab,0xaa,0xa9,0xa8,0xa7,0xa6,0xa5,0xa4,0xa3,0xa2,0xa1,0xa0,
0x9f,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96,0x95,0x94,0x93,0x92,0x91,0x90,
0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86,0x85,0x84,0x83,0x82,0x81,0x80,
0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x76,0x75,0x74,0x73,0x72,0x71,0x70,
0x6f,0x6e,0x6d,0x6c,0x6b,0x6a,0x69,0x68,0x67,0x66,0x65,0x64,0x63,0x62,0x61,0x60,
0x5f,0x5e,0x5d,0x5c,0x5b,0x5a,0x59,0x58,0x57,0x56,0x55,0x54,0x53,0x52,0x51,0x50,
0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,0x47,0x46,0x45,0x44,0x43,0x42,0x41,0x40,
0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,
0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,
0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,
0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,
};

byte TRI_TABLE[]=
{
0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,
0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,
0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,
0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,
0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf1,0xef,0xef,0xeb,0xe9,0xe7,0xe5,0xe3,0xe1,
0xdf,0xdd,0xdb,0xd9,0xd7,0xd5,0xd3,0xd1,0xcf,0xcf,0xcb,0xc9,0xc7,0xc5,0xc3,0xc1,
0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,0xaf,0xab,0xa9,0xa7,0xa5,0xa3,0xa1,
0x9f,0x9d,0x9b,0x99,0x97,0x95,0x93,0x91,0x8f,0x8f,0x8b,0x89,0x87,0x85,0x83,0x81,
0x7f,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71,0x6f,0x6f,0x6b,0x69,0x67,0x65,0x63,0x61,
0x5f,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4f,0x4b,0x49,0x47,0x45,0x43,0x41,
0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2f,0x2b,0x29,0x27,0x25,0x23,0x21,
0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0f,0x0b,0x09,0x07,0x05,0x03,0x01,
};


byte SQUARE_TABLE[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
};

byte SINE_EXP_TABLE[]= 
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,
0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x09,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x11,
0x12,0x13,0x14,0x16,0x17,0x18,0x1A,0x1B,0x1D,0x1E,0x20,0x22,0x24,0x25,0x27,0x29,
0x2B,0x2D,0x2F,0x31,0x33,0x36,0x38,0x3A,0x3D,0x3F,0x42,0x44,0x47,0x4A,0x4C,0x4F,
0x52,0x55,0x58,0x5B,0x5E,0x61,0x64,0x67,0x6B,0x6E,0x71,0x74,0x78,0x7B,0x7F,0x82,
0x86,0x89,0x8D,0x90,0x94,0x98,0x9B,0x9F,0xA2,0xA6,0xAA,0xAD,0xB1,0xB4,0xB8,0xBB,
0xBF,0xC2,0xC5,0xC9,0xCC,0xCF,0xD2,0xD5,0xD8,0xDB,0xDE,0xE1,0xE4,0xE6,0xE9,0xEB,
0xED,0xEF,0xF1,0xF3,0xF5,0xF6,0xF8,0xF9,0xFB,0xFC,0xFD,0xFD,0xFE,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xFD,0xFD,0xFC,0xFB,0xF9,0xF8,0xF6,0xF5,0xF3,0xF1,0xEF,
0xED,0xEB,0xE9,0xE6,0xE4,0xE1,0xDE,0xDB,0xD8,0xD5,0xD2,0xCF,0xCC,0xC9,0xC5,0xC2,
0xBF,0xBB,0xB8,0xB4,0xB1,0xAD,0xAA,0xA6,0xA2,0x9F,0x9B,0x98,0x94,0x90,0x8D,0x89,
0x86,0x82,0x7F,0x7B,0x78,0x74,0x71,0x6E,0x6B,0x67,0x64,0x61,0x5E,0x5B,0x58,0x55,
0x52,0x4F,0x4C,0x4A,0x47,0x44,0x42,0x3F,0x3D,0x3A,0x38,0x36,0x33,0x31,0x2F,0x2D,
0x2B,0x29,0x27,0x25,0x24,0x22,0x20,0x1E,0x1D,0x1B,0x1A,0x18,0x17,0x16,0x14,0x13,
0x12,0x11,0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x09,0x08,0x07,0x06,0x06,0x05,0x04,
0x04,0x03,0x03,0x02,0x02,0x02,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

byte PULSE_TABLE[]=
{
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

byte MIDI_TICK_TABLE[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
};

//// loOffset, hiOffset, midiCC, outputFunction, wavetable, lfoBpm, midiTime
//// Access like this: PRESETS[0][0][1]
//byte PRESETS[][4][7] = {
//  // Preset 0
//  {
//    {0,   255, 16, R_PED,     0, 0, 0},
//    {0,   255, 17, R_PED,     0, 0, 0},
//    {125, 255, 18, R_PED_INV, 0, 0, 0},
//    {125, 255, 19, R_PED_INV, 0, 0, 0}
//  },
//  // Preset 1
//  {
//    {0,   255, 16, L_PED,     0, 0, 0},
//    {0,   255, 17, L_PED,     0, 0, 0},
//    {125, 255, 18, L_PED_INV, 0, 0, 0},
//    {125, 255, 19, L_PED_INV, 0, 0, 0}
//  },
//  // Preset 2
//    {
//    {0,   255, 16, R_PED,     0, 0, 0},
//    {0,   255, 17, R_PED_INV, 0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  },
//  // Preset 3
//    {
//    {0,   255, 16, W_OUT,     0, 0, 0},
//    {0,   255, 17, R_PED,     0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  },
//  // Preset 4
//    {
//    {0,   255, 16, W_OUT,     1, 0, 0},
//    {0,   255, 17, R_PED,     0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  },
//    // Preset 5
//    {
//    {0,   255, 16, W_OUT,     2, 0, 0},
//    {0,   255, 17, R_PED,     0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  },
//    // Preset 6
//    {
//    {0,   255, 16, W_OUT,     3, 0, 0},
//    {0,   255, 17, R_PED,     0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  },
//    // Preset 7
//    {
//    {0,   255, 16, W_OUT,     4, 0, 0},
//    {0,   255, 17, R_PED,     0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  },
//    // Preset 8
//    {
//    {0,   255, 16, W_OUT,     5, 0, 0},
//    {0,   255, 17, R_PED,     0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  },
//    // Preset 9
//    {
//    {0,   255, 16, W_OUT,     0, 0, 0},
//    {0,   255, 17, W_OUT,     0, 0, 0},
//    {0,   255, 18, L_PED,     0, 0, 0},
//    {0,   255, 19, L_PED_INV, 0, 0, 0}
//  }
//
//};

void setup(void){ 

  

  
  pinMode(A_SW, INPUT);   // slower/ faster tap tempo setup
  pinMode(B_SW, INPUT);
  pinMode(tapLED, OUTPUT);  /* tap tempo led */
  
  Serial.begin(9600);     // for debug to computer
  Serial2.begin(9600);    // 9600 baud is LCD chip comm speed
  Serial3.begin(31250);     //MIDI

//*************memory test************************
    int result = memoryTest();
  Serial.print("Memory test results: ");
  Serial.print(result,DEC);
  Serial.print(" bytes free");


delay (2000); // wait for LCD to start
 
//******************setup SPI pins and initialize pots****************************

  byte clr = 0;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECTA,OUTPUT);
  pinMode(SLAVESELECTB,OUTPUT);
  digitalWrite(SLAVESELECTA,HIGH); //disable device
  digitalWrite(SLAVESELECTB,HIGH); //disable device
  
  // SPCR = 01010000
  //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
  //sample on leading edge of clk,system clock/4 (fastest)
  SPCR = (1<<SPE)|(1<<MSTR);
  clr=SPSR;
  clr=SPDR;
  delay(10);
 
  for (int i=0; i<6; i++)
  {
    write_pot_a(i,125);  //"zero" everything          ***** set this at mid-level, not zero??? problem with latching up sometimes
    write_pot_b(i,125);
  }




////*******************default setup the 4-state machine function pointers and routings********************


  functArr[0] = &LEFT_PED;              //seems to want to have these pointers in setup... can't get the Set_And_Restore function to work here... 
  functArr[1] = &LEFT_PED;
  functArr[2] = &RIGHT_PED;
  functArr[3] = &RIGHT_PED;
//
//  functArr[0] = &LEFT_PED;
//  functArr[1] = &LEFT_PED_INV;
//  functArr[2] = &RIGHT_PED;
//  functArr[3] = &RIGHT_PED_INV;
//
//  PREV_functArr[0] = &LEFT_PED;        //setup for default previous functions, will change this when user interface is designed
//  PREV_functArr[1] = &LEFT_PED_INV;
//  PREV_functArr[2] = &RIGHT_PED;
//  PREV_functArr[3] = &RIGHT_PED_INV;

//*********waveform offset defaults*******************
  bottomval[0] = 0;  
  bottomval[1] = 0;  
  bottomval[2] = 0;    
  bottomval[3] = 0;  

  topval[0] = 255;
  topval[1] = 255;
  topval[2] = 255;
  topval[3] = 255;    


 write_pot_a (4, bottomval[0]);  //setup upper and lower voltage boundaries 
 write_pot_a (5, topval[0]);
 write_pot_b (0, bottomval[1]);
 write_pot_b (1, topval[1]);
 write_pot_b (2, bottomval[2]);
 write_pot_b (3, topval[2]); 
 write_pot_b (4, bottomval[3]);
 write_pot_b (5, topval[3]);
 
 //*********************setup wavetable interrupt timer****************************
timerLoadValue=SetupTimer2(4369);        // this is 2^16 samples divided by 15, the BMP is then shifted righht by 2 (divided by another 4) 
          
                                         // thus BPM is divided by 60 with simple math

//  table_chan_1 = &SINE_TABLE[0];
//
//  table = SQUARE_TABLE;                // default waveoutput
  
//***********************encoder pinModes and interrupt setup**********************************
pinMode(encoder0PinA, INPUT); 
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
pinMode(encoder0PinB, INPUT); 
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor

pinMode(encoder1PinA, INPUT); 
  digitalWrite(encoder1PinA, HIGH);       // turn on pullup resistor
pinMode(encoder1PinB, INPUT); 
  digitalWrite(encoder1PinB, HIGH);       // turn on pullup resistor
 
// encoder0 pin A on interrupt 2 (pin 21)                //fix this text, had to switch the interrupts 
  attachInterrupt(3, doEncoder0A, CHANGE);
// encoder0 pin B on interrupt 3 (pin 20)
  attachInterrupt(2, doEncoder0B, CHANGE);  
  
// encoder1 pin A on interrupt 4 (pin 19)
attachInterrupt(5, doEncoder1A, CHANGE);
// encoder1 pin B on interrupt 5 (pin 18)
attachInterrupt(4, doEncoder1B, CHANGE);  

//****************************setup LCD display and pedalboard LEDs and display startup sequence**********************************
  Serial2.print("?G420");
  delay(100);	           // pause to allow LCD EEPROM to program: set up mode
  Serial2.print("?Bff");  // set backlight to 40 hex
  delay(100);              // pause to allow LCD EEPROM to program
  Serial2.print("?s6");   // set tabs to six spaces
  delay(1000);              // pause to allow LCD EEPROM to program
  Serial2.print("?D51515151515151515");  //special character for bargraph, alternating lines and spaces
  delay(100);
  Serial2.print("?c0");		                // turn cursor off
  delay(200);  
//  Serial2.print("?C0 Joseph Zulak 2010");  //custom boot screen
//    delay(10);	
  Serial2.print("?f");                   // clear the LCD
    delay(10);	
  Serial2.print("?S0");                  // display custom boot screen
    delay(10);	
   Serial2.print("?y0?x00?l");
   Serial2.print("1 ");
   Serial2.print("?y1?x00?l");
   Serial2.print("2 ");
   Serial2.print("?y2?x00?l");
   Serial2.print("3 ");
   Serial2.print("?y3?x00?l");
   Serial2.print("4 ");
   
  DDRF = B11111111;  // sets Arduino PORT F as OUTPUT for LED's and common matrix nibble
 // DDRK = B10110000;  // sets PORT K first nibble as input to read swicth matrix can we still use this as an anlog input??? 
  
   pinMode(62,INPUT);
   pinMode(63,INPUT);
   pinMode(64,INPUT);
    pinMode(65,INPUT);
  pinMode(66,OUTPUT);     //set up the analog pins in port K as digital outputs to power the voltage divider
  pinMode(67,OUTPUT);      //this output statemennt is probably redundant
pinMode(68,INPUT);
  digitalWrite(66,LOW);    //analog 12
  digitalWrite(67,HIGH);   //analog 13

// LED test on startup - sequentially flashes LED's on pedalboard



PORTF = led [0];
delay (150);
  
  for ( int i = 0; i < 12; i++) {  //flash 12 LED's forward
  PORTF = led[i]; 
  delay(50);                  
  }


  for ( int i = 11; i >= 0; i--) {  //flash 12 LED's backwards
  PORTF = led[i]; 
  delay(50);            
  }
 delay (100);
 PORTF = B00001111; //turn off LED's after test

  Serial2.print("?y0?x00?l");
  Set_And_Restore(0,1);
  delay (50);
  Serial2.print("?y1?x00?l");
  Set_And_Restore(1,2);
  delay (50);
  Serial2.print("?y2?x00?l");
  Set_And_Restore(2,3);
  delay (50);
  Serial2.print("?y3?x00?l");
  Set_And_Restore(3,4);
  delay (2000);

}
////tap tempo stuff for loop
//int lastslowState = LOW;
//int lastfastState = LOW;
//int slowState = LOW;
//int fastState = LOW;
//
//unsigned long currentTimer[2] = {500, 500};  /* array of most recent tap counts */
//unsigned long timeoutTime = 0;  /* this is when the timer will trigger next */
//unsigned long indicatorTimeout; /* for our fancy "blink" tempo indicator */

 int switches;
 
void loop()
{
  delay(10);
  int val = analogRead(14);  //this isn't working just get noise on the analog in
  delay(5);
  Serial.println (val);  //debug to test analog input
// *******************Code to handle input switches and light LED's************************* 
//switch positions on pedalboard:
//1  5  13  12  8  4  0
//3  7  15  14  10  6  2
//Note: there is no LED for 1,3,9,11 B00001111 turns off LED's - no switch in position 9, 11


  PORTF = strobe[zcount];                //write to matrix
  for (i = 0; i < 2; i++){                // small delay to settle port output___ note, cannot define the i variable locally
    }
//    switches = 0;
//for (int z = 65; z >= 62; z--){
//switches = switches + digitalRead(z);
//  for (i = 0; i < 2; i++){                // small delay to settle port output___ note, cannot define the i variable locally
//    }
//switches = switches <<1;
//}
//switches = switches >>1;
//switches = switches & B00001111;
//Serial.println (switches, BIN);
//  switchin = PINK;   //read input port
//PORTF = switchled[swnum];      //light up corresponding LED
 switchin = switchin & B00001111;   //mask lower nibble as we are using some higher bits for rotary selector switch


  if (switchin != B00001111 && keypress == false) {          //check for keypress - a low bit

    switch (switchin) {              //identify swicth that was pressed update "swnum"
      case B00001110:
      swnum = 0 + zcount;
      keypress = true;
      last_keypress = millis();
      break;
      case B00001101:
      swnum = 4 + zcount;
      keypress = true;
      last_keypress = millis();      
      break;
      case B00001011:
      swnum = 8 + zcount;
      keypress = true;
      last_keypress = millis();      
      break;
      case B00000111:
      swnum = 12 + zcount;
      keypress = true;
      last_keypress = millis();      
      break;  
      }  
  light_led[swnum] = true;      // have to do these crazy loops as the switch scan shares the LED matrix and cancels out the LED's - have to keep refreshing LED's
  }
  

 zcount = zcount++;        //increment stobe lines to check for keypress once though each loop to spread out load
 if (zcount > 3) {
  zcount = 0;
 }

//**************let there be LED light*******************

for (i = 0; i < 16; i++)   {          // priority flash checks all keys
  if (light_led[i] == true)   
     flash_LED(i);
}
for (i = 0; i < 16; i++)   {          //will flash on utility mode one key "outstanding" at a time.... 
  if (blink_led[i] == true && blink_disable == false) {
     blink_LED(i);
     break;
  }
}

if (millis() - last_keypress > 600 && keypress == true) {      //debounce and avoid repeating loop
  keypress = false;
  Serial.print(swnum);
  }

 phaseDelta = BPM >> 2; // divide by 4 to get BPM to Hz for the lookup table ... needed in loop 

//*********************** read user input switches *****************************  // needs offset function - sw 0 or 2, then select channel

//midi clock output

  if (swnum == 7 && midi_clock_flag == false) {
    start_flag = true;
    midi_clock_flag = true;
  }

  if (swnum == 5) {
    midi_clock_flag = false;
    Serial3.print(midi_stop, BYTE);
  }



//*******channel 1***********
//***set***
if (swnum == 15 && HOLD_FLAG[0] == false && Set_Lower == false && Set_Upper == false) {       //no lock or offset functions
  Serial2.print("?y0?x00?l");
  Set_Functions(0, 1); 
}
 
if (swnum == 15 && HOLD_FLAG[3] == false && Set_Lower == true && function[0] < 4 ) {   //set lower offset mode
  swnum = 9; 
  if (Save_Lower[0] == false) {  //first time through to select channel
    Serial2.print("?y0?x00?l"); 
    Set_Lower_Offset_A(0, 1); 
    blink_led[15] = true;
  }
  else {                          //second time through to save lower setting
    Serial2.print("?y0?x00?l"); 
    Set_Lower_Offset_B(0, 1); 
    blink_led[15] = false;
  }
}     
//***lock***

if (swnum == 13 && HOLD_FLAG[0] == false && Set_Lower == false && Set_Upper == false) {         // no hold or offset functions
    Serial2.print("?y0?x00");
    Lock_Functions(0); 
}

if (swnum == 13 && HOLD_FLAG[0] == false && function[0] < 4 && Set_Upper == true) {       //set upper offset mode
  swnum = 9; 
  if (Save_Upper[0] == false) {  //first time through to select channel
    Serial2.print("?y0?x00?l"); 
    Set_Upper_Offset_A(0, 1); 
    blink_led[13] = true;
  }
  else {                          //second time through to save upper setting
    Serial2.print("?y0?x00?l"); 
    Set_Upper_Offset_B(0, 1); 
    blink_led[13] = false;
  }
}


//****restore**** 
if (swnum == 15 && HOLD_FLAG[0] == true) {
    Serial2.print("?y0?x00?l");
    Restore_Functions(0, 1); 
}

//*******channel 2***********************
//****set****
if (swnum == 14 && HOLD_FLAG[1] == false && Set_Lower == false && Set_Upper == false) {       //no lock or offset functions
  Serial2.print("?y1?x00?l");
  Set_Functions(1, 2);   
}

if (swnum == 14 && HOLD_FLAG[1] == false && Set_Lower == true && function[1] < 4 ) {
  swnum = 9; 
  if (Save_Lower[1] == false) {  //first time through to select channel
    Serial2.print("?y1?x00?l"); 
    Set_Lower_Offset_A(1, 2); 
    blink_led[14] = true;
  }
  else {                          //second time through to save lower setting
    Serial2.print("?y1?x00?l"); 
    Set_Lower_Offset_B(1, 2); 
    blink_led[14] = false;
  }
}   

//****lock*****

if (swnum == 12 && HOLD_FLAG[1] == false && Set_Lower == false && Set_Upper == false) {         // no hold or offset functions
    Serial2.print("?y1?x00");
    Lock_Functions(1); 
}

if (swnum == 12 && HOLD_FLAG[1] == false && function[1] < 4 && Set_Upper == true) {        
  swnum = 9; 
  if (Save_Upper[1] == false) {  //first time through to select channel
    Serial2.print("?y1?x00?l"); 
    Set_Upper_Offset_A(1, 2);
    blink_led[12] = true; 
  }
  else {                          //second time through to save upper setting
    Serial2.print("?y1?x00?l"); 
    Set_Upper_Offset_B(1, 2);
    blink_led[12] = false; 
  }
}

//*****restore***** 
if (swnum == 14 && HOLD_FLAG[1] == true) {
    Serial2.print("?y1?x00?l");
    Restore_Functions(1, 2); 
}

//*********************channel 3***************************
//***set***
if (swnum == 10 && HOLD_FLAG[2] == false && Set_Lower == false && Set_Upper == false) {       //no lock or offset functions
  Serial2.print("?y2?x00?l");
  Set_Functions(2, 3); 
}

if (swnum == 10 && HOLD_FLAG[2] == false && Set_Lower == true && function[2] < 4 ) {
  swnum = 9; 
  if (Save_Lower[2] == false) {  //first time through to select channel
    Serial2.print("?y2?x00?l"); 
    Set_Lower_Offset_A(2, 3);
    blink_led[10] = true; 
  }
  else {                          //second time through to save lower setting
    Serial2.print("?y2?x00?l"); 
    Set_Lower_Offset_B(2, 3); 
    blink_led[10] = false;
  }
}   
    
//***lock***


if (swnum == 8 && HOLD_FLAG[2] == false && Set_Lower == false && Set_Upper == false) {         // no hold or offset functions
    Serial2.print("?y2?x00");
    Lock_Functions(2); 
}

if (swnum == 8 && HOLD_FLAG[2] == false && function[2] < 4 && Set_Upper == true) {       
  swnum = 9; 
  if (Save_Upper[2] == false) {  //first time through to select channel
    Serial2.print("?y2?x00?l"); 
    Set_Upper_Offset_A(2, 3); 
    blink_led[8] = true;
  }
  else {                          //second time through to save upper setting
    Serial2.print("?y2?x00?l"); 
    Set_Upper_Offset_B(2, 3); 
    blink_led[8] = false;
  }
} 
//****restore**** 
if (swnum == 10 && HOLD_FLAG[2] == true) {
    Serial2.print("?y2?x00?l");
    Restore_Functions(2, 3); 
}


//*********************channel 4****************************
//****set****

if (swnum == 6 && HOLD_FLAG[3] == false && Set_Lower == false && Set_Upper == false) {       //no lock or offset functions
     Serial2.print("?y3?x00?l");
     Set_Functions(3, 4); 
  }

  
if (swnum == 6 && HOLD_FLAG[3] == false && Set_Lower == true && function[3] < 4 ) {
  swnum = 9; 
  if (Save_Lower[3] == false) {  //first time through to select channel
    Serial2.print("?y3?x00?l");
    Set_Lower_Offset_A(3, 4); 
    blink_led[6] = true;
  }
  else {                          //second time through to save lower setting
    Serial2.print("?y3?x00?l"); 
    Set_Lower_Offset_B(3, 4); 
    blink_led[6] = false;
  }
}   
//****lock*****
if (swnum == 4 && HOLD_FLAG[3] == false && Set_Lower == false && Set_Upper == false) {         // no hold or offset functions
    Serial2.print("?y3?x00");
    Lock_Functions(3); 
}

if (swnum == 4 && HOLD_FLAG[3] == false && function[3] < 4 && Set_Upper == true) {        //need to look at save upper!!!
  swnum = 9; 
  if (Save_Upper[3] == false) {  //first time through to select channel
    Serial2.print("?y3?x00?l"); 
    Set_Upper_Offset_A(3, 4); 
    blink_led[4] = true;
  }
  else {                          //second time through to save upper setting
    Serial2.print("?y3?x00?l"); 
    Set_Upper_Offset_B(3, 4); 
    blink_led[4] = false;
  }
}

//****restore*****  
if (swnum == 6 && HOLD_FLAG[3] == true) {
    Serial2.print("?y3?x00?l");
    Restore_Functions(3, 4); 
}

//*************utility Parameters ***************

if (swnum == 2) {
  swnum = 9; 
  Set_Lower = true;
  blink_led[2] = true;
}

if (swnum == 0) {
    swnum = 9; 
  Set_Upper = true;
  blink_led[0] = true;
 
}

//for (i=0; i < 4; i++) {                // make sure we clear all the states that set the upper and lower offsets
//  if (Save_Upper[i] == true) {
//  Set_Upper = true;
//    break;
//  }
//  Set_Upper = false;
//}

//for (i=0; i < 4; i++) {
//  if (Save_Lower[i] == true) {
//  Set_Lower = true;
//    break;
//  }
//  Set_Lower = false;
//}  
    
//********************************update MIDI and OFFSET values******************************
/* WRITE VOLTAGE BIAS TO ALL CHANNELS
  
  POT A 0-3 are outputs
  POT A 4 - lower POT 0 Bias
  POT A 5 - upper POT 0 Bias
  
  POT B 0 - lower POT 1 Bias
  POT B 1 - upper POT 1 Bias
  POT B 2 - lower POT 2 Bias
  POT B 3 - upper POT 2 Bias
  POT B 4 - lower POT 3 Bias
  POT B 5 - upper POT 3 Bias
 */
 for(int i = 0; i < 4; ++i) {                  //write MIDI and offsets out once per loop
    
    if (MIDIVout[i] == true)  {
      int MIDIVal = Vout[i]/2;
      MIDIcntrl(0xb0, MIDIcc[i], MIDIVal);      // to midi channel 1, cc number from array
      MIDIVout[i] = false;
     }
 }   
    Offset_Adjust();                            // function to write offsets once per loop
    


//************************* tap tempo code*****************************

  if (BPM <= 45)                 //set a percentage of tap time to increase or decrease
    tapDelta = ((currentTimer[0] + currentTimer[1])/2)*.05; 
  else 
    tapDelta = ((currentTimer[0] + currentTimer[1])/2)*.03;             
  
  slowState = digitalRead(A_SW);
  fastState = digitalRead(B_SW);
  
  // if slower button (A_SW) pressed, call function to increase count of tap registers || slow DOWN ||
  if( slowState == LOW && slowState != lastslowState && fastState == HIGH)
  {
    slowerTap(); /* we got a HIGH-LOW transitionon only the A switch, call slowerTap function */
    disp_BPM();
  }
  // if faster button pressed (B_SW), call function to decrease count of tap registers || speed UP || 
  if( fastState == LOW && fastState != lastfastState && slowState == HIGH )
  {
    fasterTap(); /* we got a HIGH-LOW transition, call our tap() function */
    disp_BPM();
  }
  if(  slowState == LOW && fastState == LOW && slowState != lastslowState )  
  {
    tap(); /* we got a HIGH-LOW transition, call our tap() function */
   // disp_BPM();
  }

  lastfastState = fastState; /* keep track of the state */
  lastslowState = slowState; /* keep track of the state */

  /* check for timer timeout  - only using this for blinking lLED during tap temp read and we disable wavetable blinks*/
  if( millis() >= timeoutTime )
  {
    /* timeout happened.  clock tick! */
    indicatorTimeout = millis() + 40;  /* this sets the time when LED goes off */
    /* and reschedule the timer to keep the pace */
    rescheduleTimer();
  }

  /* display the tap blink  LED */

  if( millis() < indicatorTimeout && inhibit_LED == true) {   //this is active when reading BPM and down't want distracting wavetable blinks 
    digitalWrite( wave_led_pin, HIGH );                        //at another tempo
  }
  else {
    digitalWrite( wave_led_pin, LOW );
  }
 
 
 

  
//****************DISPLAY STUFF*****************************


 for (int i = 0; i < 4; i++) {
 if (wave_channel[i] == 0) {
   BARGRAPH (i);
 }
 }
}  //loop end 




// void setDefaultPresets() {
//   for (int idx = 0; idx < NUM_PRESETS; ++idx) {
//     for (int chan = 0; chan < NUM_CHANNELS; ++chan) {
//       //         Idx       chan       loOff   hiOff     midiCc  funct   wave    lfoBpm  midiTime
//       saveChannelPreset(idx,      chan,      0,      255,      0,      0,      0,      0,      0);
//     }
//   }
// }
// 
// void saveChannelPreset(int idx, int channel, int lowOffset, int hiOffset, int midiCC, int outputFunct, int wavetable, int lfoBpm, int midiTime) {
//   int offset = PRESET_OFFSET + (idx * PRESET_SIZE) + (channel * CHAN_PRESET_SIZE);
//   EEPROM.write(offset++, lowOffset);
//   EEPROM.write(offset++, hiOffset);
//   EEPROM.write(offset++, midiCC);
//   EEPROM.write(offset++, outputFunct);
//   EEPROM.write(offset++, wavetable);
//   EEPROM.write(offset++, lfoBpm);
//   EEPROM.write(offset++, midiTime);
// }
// 
// void loadPreset(int idx) {
//   int offset = idx * PRESET_SIZE;
//   for (int i = 0; i < PRESET_SIZE; ++i) {
//     presets[offset + i] = EEPROM.read(offset + i + PRESET_OFFSET);
//   }
// }
// 
// void loadPresets() {
//   for (int i = 0; i < NUM_PRESETS; ++i) {
//     loadPreset(i);
//   }
// }
// 
// void selectPreset(int idx) {
//   int presetOffset = idx * PRESET_SIZE;
//   topval[0] = presets[presetOffset];
//   topval[1] = presets[presetOffset + 1 * CHAN_PRESET_SIZE];
//   topval[2] = presets[presetOffset + 2 * CHAN_PRESET_SIZE];
//   bottomval[0] = presets[presetOffset + 1];
//   
//   // set current preset variable
// }

//void saveCurrentPreset() {
//  EEPROM.write(CURRENT_PRESET_ADDRESS, currentPreset);
//};
//
//int getCurrentPreset() {
//  return EEPROM.read(CURRENT_PRESET_ADDRESS);
//}

// this function will return the number of bytes currently free in RAM
int memoryTest() {
  int byteCounter = 0; // initialize a counter
  byte *byteArray; // create a pointer to a byte array
  // More on pointers here: http://en.wikipedia.org/wiki/Pointer#C_pointers

  // use the malloc function to repeatedly attempt allocating a certain number of bytes to memory
  // More on malloc here: http://en.wikipedia.org/wiki/Malloc
  while ( (byteArray = (byte*) malloc (byteCounter * sizeof(byte))) != NULL ) {
    byteCounter++; // if allocation was successful, then up the count for the next try
    free(byteArray); // free memory after allocating it
  }
  
  free(byteArray); // also free memory after the function finishes
  return byteCounter; // send back the highest number of bytes successfully allocated
}

//************************************************pedal functions*****************************
//***********user interface - select function**********

void Set_Functions(byte chan, byte line) {        // increments the case each time channel switch is hit 
  function[chan] = function[chan]++;              // cycles through output options
  if (function[chan] > 9) {
    function[chan] = 0;          //reset
  }
  swnum = 9;      // null switch
  Set_And_Restore(chan, line);
}
void Set_And_Restore(byte chan, byte line) {     //logic to assign output according to switch presses
//  disp_BPM();
  switch (function[chan]) {
      case 0:
      functArr[chan] = &LEFT_PED;
      Serial2.print(line, DEC);
      Serial2.print(" Left Ped");
      disp_BPM();
      break;
      case 1:
      functArr[chan] = &LEFT_PED_INV;
      Serial2.print(line, DEC);
      Serial2.print(" INV Left Ped");      
      disp_BPM();
      break;
      case 2: 
      functArr[chan] = &RIGHT_PED;
      Serial2.print(line, DEC);
      Serial2.print(" Right Ped");
      disp_BPM();
      break;
      case 3:
      functArr[chan] = &RIGHT_PED_INV;
      Serial2.print(line, DEC);
      Serial2.print(" INV Right Ped");
      disp_BPM();
      break;
      case 4:
      functArr[chan] = &WAVEOUT;
      waveArr[chan] = &SQUARE_TABLE[0];
//      table = SQUARE_TABLE;
      HI_LOW_OFFSET[chan] = true;
      Serial2.print(line, DEC);
      Serial2.print(" LFO Sqr   BPM:");
      disp_BPM();
      break;
      case 5:
      functArr[chan] = &WAVEOUT;
      waveArr[chan] = &TRI_TABLE[0];
      HI_LOW_OFFSET[chan] = true;
      Serial2.print(line, DEC);
      Serial2.print(" LFO Tri   BPM:");
      disp_BPM();
      break;
      case 6:
      functArr[chan] = &WAVEOUT;
      waveArr[chan] = &SINE_TABLE[0];
      HI_LOW_OFFSET[chan] = true;
      Serial2.print(line, DEC);
      Serial2.print(" LFO Sine  BPM:");
      disp_BPM();
      break;
      case 7:
      functArr[chan] = &WAVEOUT;
      waveArr[chan] = &SINE_EXP_TABLE[0];
      HI_LOW_OFFSET[chan] = true;
      Serial2.print(line, DEC);
      Serial2.print(" LFO Sine1 BPM:");
      disp_BPM();
      break;
      case 8:
      functArr[chan] = &WAVEOUT;
      waveArr[chan] = &SAW_TABLE[0];
      HI_LOW_OFFSET[chan] = true;
      Serial2.print(line, DEC);
      Serial2.print(" LFO Ramp  BPM:");
      disp_BPM();
      break;
      case 9:
      functArr[chan] = &WAVEOUT;
      waveArr[chan] = &SAW_REV_TABLE[0];
      HI_LOW_OFFSET[chan] = true;
      Serial2.print(line, DEC);
      Serial2.print(" LFO Saw   BPM:");
      disp_BPM();
      break;
    }
}

//***********user interface - lock and restore voltage output**********

void Lock_Functions(byte chan)            // holds the output voltage for expr pedal, upper and lower offsets for waveform
 {                      
  Serial2.print("H");
  swnum = 9;    //null switch  
  functArr[chan] = &HOLD_CHAN;
  HOLD_FLAG[chan] = true;                      // restore previous function instead of going through switch statement
  HI_LOW_OFFSET[chan] = false;
  if (function[chan] < 4) {                    // erases any text hanging around and displays graph
  disp_bargraph = true;
  BARGRAPH(chan);
  }
}
void Restore_Functions(byte chan , byte line)      // restores previous output functions and restores voltage output
  {
  swnum = 9;  //null switch
    //revert to last need more 
  HOLD_FLAG[chan] = false;
  HI_LOW_OFFSET[chan] = true;
  Set_And_Restore(chan, line); 
  }
 
 //***********user interface - set upper offset**********
  
void Set_Upper_Offset_A(byte chan, byte line)  {    // may want to incorporate upper and lower offsets  when seetting voltage levels for more accuracy
  blink_led[0] = false;
  Save_Upper[chan] = true;
  Serial2.print(line, DEC);
  Serial2.print(" CHAN to SAVE UP");       // almost works......
  if (function[chan] < 2)  {
    functArr[chan] = &LEFT_PED_UPPER_OFFSET;
  }
  else   {
    functArr[chan] = &RIGHT_PED_UPPER_OFFSET;
  }
//  old_bottomval[chan] = bottomval[chan];
//  bottomval[chan] = 0;
//  bottom_offset[chan] = true;
  topval[chan] = 255;
  top_offset[chan] = true; 
}

void Set_Upper_Offset_B(byte chan, byte line) {
  Save_Upper[chan] = false; 
//  Set_Upper = false; 
for (i=0; i < 4; i++) {                // make sure we clear all the states that set the upper and lower offsets
  if (Save_Upper[i] == true) {          // check its neighbors before clearing flag
  Set_Upper = true;
    break;
  }
  Set_Upper = false;
}
  Serial2.print(line, DEC);
  Serial2.print(" Upper Limit SAVED"); 
  switch (function[chan]) {
    case 0:  
       functArr[chan] = &LEFT_PED;
       break;
    
     case 1:

       functArr[chan] = &LEFT_PED_INV;
       break;
       
     case 2:  
       functArr[chan] = &RIGHT_PED;
       break;
    
     case 3:

       functArr[chan] = &RIGHT_PED_INV;
       break;         
    }
    bottomval[chan] = old_bottomval[chan];
    bottom_offset[chan] = true;
    old_topval[chan] = topval[chan];            // in case both top and bottom offsts are being set at the same time
}

//***********user interface - set lower offset**********

void Set_Lower_Offset_A(byte chan, byte line)  {     //removes any ofsets and runs original function until chan is hit again
    blink_led[2] = false;
                                 // "B" function then saves the offset after chan is hit
    Save_Lower[chan] = true;
    Serial2.print(line, DEC);
    Serial2.print(" CHAN to SAVE DN");       // almost works......
    if (function[chan]  < 2)  {
      functArr[chan] = &LEFT_PED_LOWER_OFFSET;
      }
    else   {
      functArr[chan] = &RIGHT_PED_LOWER_OFFSET;
      }
//  old_topval[chan] = topval[chan];
//  topval[chan] = 255;
//  top_offset[chan] = true;
     bottomval[chan] = 0;
     bottom_offset[chan] = true; 
}


void Set_Lower_Offset_B(byte chan, byte line) {
  Save_Lower[chan] = false; 
for (i=0; i < 4; i++) {
  if (Save_Lower[i] == true) {      // check neighbours beforee clearing flag
  Set_Lower = true;
    break;
  }
  Set_Lower = false;
}  
  Serial2.print(line, DEC);
  Serial2.print(" Lower Limit SAVED"); 
  switch (function[chan]) {
    case 0:  
//       bottomval[chan] = (encoder1Pos *2);
//       bottom_offset[chan] = true; 
//       encoder1Pos = 0;              //??
       functArr[chan] = &LEFT_PED;
       break;
    
     case 1:
//       bottomval[chan] = encoder1Pos *2;
//       bottom_offset[chan] = true; 
       functArr[chan] = &LEFT_PED_INV;
       break;
       
     case 2:  
//       bottomval[chan] = max (0, ((encoder0Pos *2) - 15));
//       bottom_offset[chan] = true; 
//         encoder0Pos = 0;    //??  have to temporaroly subtract the lower offset from the pedal to avoid jump???
       functArr[chan] = &RIGHT_PED;
       break;
    
     case 3:
//       bottomval[chan] = encoder0Pos *2;
//       bottom_offset[chan] = true; 
       functArr[chan] = &RIGHT_PED_INV;
       break;         
    }
    topval[chan] = old_topval[chan];
    top_offset[chan] = true;
    old_bottomval[chan] = bottomval[chan];    // in case both top and bottom offsts are being set at the same time
}
  



//**************** adjust offsets********************
void Offset_Adjust() {
    if (bottom_offset[0] == true) {              // remainder are top and bottom offsets
       write_pot_a (4, bottomval[0]);
       bottom_offset[0] = false;
     }  
 
   if (bottom_offset[1] == true) {
       write_pot_b (0, bottomval[1]);
       bottom_offset[1] = false;
     } 
     
   if (bottom_offset[2] == true) {
       write_pot_b (2, bottomval[2]);
       bottom_offset[2] = false;
     }      
     
   if (bottom_offset[3] == true) {
       write_pot_b (4, bottomval[3]);     
       bottom_offset[3] = false;
     }      
 
   if (top_offset[0] == true) {
       write_pot_a (5, topval[0]);  
       top_offset[0] = false;
     }
     
   if (top_offset[1] == true) {
       write_pot_b (1, topval[1]);
       top_offset[1] = false;
     }
     
   if (top_offset[2] == true) {
       write_pot_b (3, topval[2]); 
       top_offset[2] = false;
     }
     
   if (top_offset[3] == true) {
       write_pot_b (5, topval[3]);
       top_offset[3] = false;
     }
  }   
//*********************** state machine functions*************************

// these functions pass Vout for display only, and to SPI device channels 1-4 ---> 


void RIGHT_PED(int channel) {                      //RIGHT PEDAL output function                       
  wave_channel[channel] = 0;
  if (encoder0Pos != old_encoder0Pos[channel]) 
  {
  Vout[channel] = (((topval[channel] - bottomval[channel]) * encoder0Pos) / 127) + bottomval[channel];              
  MIDIVout[channel] = true;
//  VoutCR[channel] = 2;
  potval = encoder0Pos * 2;                       //to SPI device  
  write_pot_a(channel, potval); 
  old_encoder0Pos[channel] = encoder0Pos;
  }
}

void RIGHT_PED_INV(int channel) {                      //RIGHT PEDAL inverted output function                    
  wave_channel[channel] = 0;
  if (encoder0Pos != old_encoder0Pos[channel]) 
  {
  Vout[channel] = (((topval[channel] - bottomval[channel]) * abs(encoder0Pos - 127)) / 127) + bottomval[channel];           
  MIDIVout[channel] = true;
//  VoutCR[channel] = 2;
  potval = abs((encoder0Pos - 127)*2);                 
  write_pot_a(channel, potval);   
  old_encoder0Pos[channel] = encoder0Pos;
  }
}

void LEFT_PED(int channel) {                      //LEFT PEDAL output function     
  wave_channel[channel] = 0;
  if (encoder1Pos != old_encoder1Pos[channel]) 
  {
  Vout[channel] = (((topval[channel] - bottomval[channel]) * encoder1Pos) / 127) + bottomval[channel];             
  MIDIVout[channel] = true;
//  VoutCR[channel] = 2;
  potval = encoder1Pos * 2;                   
  write_pot_a(channel, potval);    
  old_encoder1Pos[channel] = encoder1Pos;
  }
}

void LEFT_PED_INV(int channel) {                      //LEFT PEDAL inverted output function     
  wave_channel[channel] = 0;
  if (encoder1Pos != old_encoder1Pos[channel]) 
  { 
  Vout[channel] = (((topval[channel] - bottomval[channel]) * abs(encoder1Pos - 127)) / 127) + bottomval[channel];            
  MIDIVout[channel] = true;
//  VoutCR[channel] = 2;
  potval = abs((encoder1Pos - 127)*2);                 
  write_pot_a(channel, potval);   
  old_encoder1Pos[channel] = encoder1Pos;
  }
}
//*********************utility functions************************

  

void RIGHT_PED_UPPER_OFFSET(int channel) {
     wave_channel[channel] = 0;
     if (encoder0Pos != old_encoder0Pos[channel])  {
     write_pot_a(channel, 255); 
    Vout[channel] = max(bottomval[channel] + 20, encoder0Pos*2); // minimum to leave a gap between offsets for bargraph function            
    MIDIVout[channel] = true;
    topval[channel] = Vout[channel];
    top_offset[channel] = true;  
    old_encoder0Pos[channel] = encoder0Pos;
     }
}


void LEFT_PED_UPPER_OFFSET(int channel) {
     wave_channel[channel] = 0;
     if (encoder1Pos != old_encoder1Pos[channel])  {
     write_pot_a(channel, 255); 
    Vout[channel] = max(bottomval[channel]+ 20, encoder1Pos*2);             
    MIDIVout[channel] = true;
    topval[channel] = Vout[channel];
    top_offset[channel] = true;  
    old_encoder1Pos[channel] = encoder1Pos;
     }
}

void RIGHT_PED_LOWER_OFFSET(int channel) {
     wave_channel[channel] = 0;
     if (encoder0Pos != old_encoder0Pos[channel])  {
     write_pot_a(channel, 0); 
         Vout[channel] = min(topval[channel] - 20, encoder0Pos*2); 
//    Vout[channel] = (((topval[channel] - bottomval[channel]) * encoder0Pos) / 127) + bottomval[channel];             
    MIDIVout[channel] = true;
    bottomval[channel] = Vout[channel];
    bottom_offset[channel] = true;  
    old_encoder0Pos[channel] = encoder0Pos;
     }
}

void LEFT_PED_LOWER_OFFSET(int channel) {
     wave_channel[channel] = 0;
     if (encoder1Pos != old_encoder1Pos[channel])  {
     write_pot_a(channel, 0); 
         Vout[channel] = min(topval[channel] - 20, encoder1Pos*2); 
//    Vout[channel] = (((topval[channel] - bottomval[channel]) * encoder1Pos) / 127) + bottomval[channel];             
    MIDIVout[channel] = true;
    bottomval[channel] = Vout[channel];
    bottom_offset[channel] = true;  
    old_encoder1Pos[channel] = encoder1Pos;
    }    
}

void HOLD_CHAN(int channel) {
}

void WAVEOUT(int channel) {
//  if (VoutCR[channel] != 9) {    //test for toggle that LCD wrote a note once, avoid flickering message
//    VoutCR[channel] = 0;
//  }
  wave_channel[channel] = 1;
    if (encoder0Pos != old_encoder0Pos[channel] && HI_LOW_OFFSET[channel] == true) {
    topval[channel] = encoder0Pos *2;
    top_offset[channel] = true;
    old_encoder0Pos[channel] = encoder0Pos;  
    }
    
    if (encoder1Pos != old_encoder1Pos[channel] && HI_LOW_OFFSET[channel] == true) {
    bottomval[channel] = encoder1Pos *2;
    bottom_offset[channel] = true;  
    old_encoder1Pos[channel] = encoder1Pos;
    }  
}

 //******************LIGHT LED************************

 void flash_LED(byte lednum) {

   if (millis() -  last_keypress <  500) {
     PORTF = switchled[lednum];
     blink_disable = true;
   }
   else {
     PORTF = switchled[9];
     blink_disable = false;
     light_led[lednum] = false;
   }
 } 


 int B_ledState = LOW;             // ledState used to set the LED
 unsigned long B_previousMillis = 0;        // will store last time LED was updated

 
 void blink_LED(byte lednum)  {
   // here is where you'd put code that needs to be running all the time.
   // check to see if it's time to blink the LED; that is, is the difference
   // between the current time and last time we blinked the LED bigger than
   // the interval at which we want to blink the LED.
   if (millis() -  B_previousMillis > 200) {
     // save the last time you blinked the LED 
     B_previousMillis = millis();   
     // if the LED is off turn it on and vice-versa:
     if (B_ledState == LOW) {
       B_ledState = HIGH;
     }
     else  
        B_ledState = LOW; 
   }
   if (B_ledState == HIGH)
     PORTF = switchled[lednum];
   if (B_ledState == LOW)
     PORTF = switchled[9];  
 } 
   
//**************** BARGRAPH DISPLAY STUFF*****************************

void BARGRAPH(byte chan) {
    Num_5 = Vout[chan] * 0.07;                   
    if (curs[chan] > Num_5 && millis() - last_keypress >1000 || disp_bargraph == true){ 
      disp_bargraph = false;
      Serial2.print("?x02");       //bar forward first is to print over any writing with a bargraph
      Serial2.print("?y");         
      Serial2.print(chan, DEC);
      bar_fwd();
      Serial2.print("?x20"); 
      Serial2.print("?y");         
      Serial2.print(chan, DEC);
      bar_back();
      curs[chan] = Num_5;
    }
    else if (curs[chan] < Num_5 && millis() - last_keypress >1000 ) {      // change if need be
      Serial2.print("?x20");    //rub out any printing under... 
      Serial2.print("?y");         
      Serial2.print(chan, DEC);
      bar_back();
      
      Serial2.print("?x02");       // cursor to beginning of line "chan"
      Serial2.print("?y");     
      Serial2.print(chan, DEC);
      bar_fwd();
      curs[chan] = Num_5;
      }  
   }     


 
 
 // two functions to add / delete bars in bargraph display 
 void bar_fwd () {
          for (int i = 0; i <= Num_5; i++){ 
           Serial2.print("?5");          // print custom character 5 - solid block tiles
//           delay(1);    
          }
  }
 
 void bar_back () {
     for (int i = 17; i>=Num_5; i--){  
         Serial2.print("?b");
//         delay(1);  
     }
 }




//*******************************************************************  
//function to write SPI to digital pots
byte write_pot_a(int address, int value)      // chan 1, 2, 3, 4 output and offsets for chan 1
{
  digitalWrite(SLAVESELECTA,LOW);     
  //2 byte opcode
  cli();
  spi_transfer(address);
  spi_transfer(value);
  digitalWrite(SLAVESELECTA,HIGH); //release chip, signal end transfer
  sei();
}
byte write_pot_b(int address, int value)
{
  digitalWrite(SLAVESELECTB,LOW);            //offset outputs
  //2 byte opcode
  cli();
  spi_transfer(address);
  spi_transfer(value);
  digitalWrite(SLAVESELECTB,HIGH); //release chip, signal end transfer
  sei();
}
// SPI protocol
char spi_transfer(volatile char data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  return SPDR;                    // return the received byte
}

//**************************tap tempo stuff***************
//volatile boolean inhibit_LED = false;
byte ctr;
unsigned long lastTap = 0; /* when the last tap happened */
void tap()
{
  /* we keep two of these around to average together later */

  if (millis() - lastTap > 100)  //check for garbage bounces
  {
    currentTimer[1] = currentTimer[0];
    currentTimer[0] = millis() - lastTap;
    lastTap = millis();
    timeoutTime = 0; /* force the trigger to happen immediately - sync and blink! */
    phase= 0; //synchronize the LFO during foot taps - but not during midi clock in - just once at start of midi clock
    if (currentTimer[0] > (currentTimer[1] + 500))
    {
     ctr = 0;
     disp_TAP(); 
     inhibit_LED = true; 
    }
    else 
    {
      ctr++;  
    }
    if (ctr > 3)
    {
      inhibit_LED = false;
      disp_BPM();
    }
  }
}
void rescheduleTimer()
{
  /* set the timer to go off again when the time reaches the 
   timeout.  The timeout is all of the "currentTimer" values averaged
   together, then added onto the current time.  When that time has been
   reached, the next tick will happen...
   */
  timeoutTime = millis() + ((currentTimer[0] + currentTimer[1])/2);
}

void slowerTap()
{
  /* function to increase time interval of tap by constant tapDelta 
   */
  for (int i = 0; i < 2; i++) {
    int timerInc = currentTimer[i] + tapDelta;
    currentTimer[i] = min(timerInc, 7500);     //  max timer value to end up with 8 BPM  - to work with a divide by 4 in code
  }
}

void fasterTap()
{
  /* function to decrease time interval of tap by constant tapDelta 
   */
  for (int i = 0; i < 2; i++) {
    int timerDec = currentTimer[i] - tapDelta;
    currentTimer[i] = max(timerDec, 35);  // min time value to get a max freq of just less than 30 Hz or 1700 BPM
                                          // code seems to crap out over 1800 BPM, possibly over the sampling freq or something? where is the limit? 
  }
}


byte resume = 0;
void disp_BPM()  {
   BPM = 120000/(currentTimer[0] + currentTimer[1]);
   for (int i = 0; i < 4; i++) {
     if  (wave_channel[i] == 1) {
       Serial2.print("?x12");
       Serial2.print("?y");
       Serial2.print(i, DEC); 
       Serial2.print("BPM:"); 
       Serial2.print("?x20");
       Serial2.print("?y");
       Serial2.print(i, DEC);   
       Serial2.print("?b?b?b?b");
       Serial2.print(BPM);
       resume = i + 1;
       break;
     }
   }  
  for (int i = resume; i < 4; i++) {  //does this cause a problem if resume = 3?
    if  (wave_channel[i] == 1) {      //wipes the remaining lines if line is higher (y is smaller) need it here too, if channel changes without new BPM
       Serial2.print("?x20");
       Serial2.print("?y");
       Serial2.print(i, DEC);   
       Serial2.print("?b?b?b?b?b?b?b?b");     
    }
  }   
}
//byte resume = 0;
void disp_TAP()
  {
//   BPM = 120000/(currentTimer[0] + currentTimer[1]);
   for (int i = 0; i < 4; i++) {
     if  (wave_channel[i] == 1) {
       Serial2.print("?x12");
       Serial2.print("?y");
       Serial2.print(i, DEC); 
       Serial2.print("READ BPM"); 
//       Serial2.print("?x20");
//       Serial2.print("?y");
//       Serial2.print(i, DEC);   
//       Serial2.print("?b?b?b?b");
//       Serial2.print(BPM);
       resume = i + 1;
       break;
     }
   }  
  for (int i = resume; i < 4; i++) {  //does this cause a problem if resume = 3?
    if  (wave_channel[i] == 1) {      //wipes the remaining lines if line is higher (y is smaller) 
       Serial2.print("?x20");
       Serial2.print("?y");
       Serial2.print(i, DEC);   
       Serial2.print("?b?b?b?b?b?b?b?b");     
    }
  }   
}

//******************************** MIDI OUT STUFF****************************

 //  outputs MIDI control on channel 0.  Doesn't check to see that
 //  cmd is greater than 127, or that data values are  less than 127:
 void MIDIcntrl(int cmd, int cntrl, int value) {
   Serial3.print(cmd, BYTE);
   Serial3.print(cntrl, BYTE);
   Serial3.print(value, BYTE);
 }


//interrupt code to read RIGHT linear encoder
void doEncoder0A(){

  // look for a low-to-high on channel A
  if (digitalRead(encoder0PinA) == HIGH) { 
    // check channel B for encoder direction
    if (digitalRead(encoder0PinB) == LOW) {  
      encoder0Pos++;                         // CW
      encoder0Pos = min(encoder0Pos, 127);
    } 
    else {
      encoder0Pos--;                         // CCW
      encoder0Pos = max(encoder0Pos, 0);
    }
  }
  else   // must be a high-to-low edge on channel A                                       
  { 
    // check channel B for encoder direction
    if (digitalRead(encoder0PinB) == HIGH) {   
      encoder0Pos++;          // CW
      encoder0Pos = min(encoder0Pos, 127);     
    } 
    else {
      encoder0Pos--;          // CCW
      encoder0Pos = max(encoder0Pos, 0); 
    }
  }
}

void doEncoder0B(){

  // look for a low-to-high on channel B
  if (digitalRead(encoder0PinB) == HIGH) {   
    // check channel A for encoder direction
    if (digitalRead(encoder0PinA) == HIGH) {  
      encoder0Pos++;         // CW
      encoder0Pos = min(encoder0Pos, 127);  
    } 
    else {
      encoder0Pos--;         // CCW
      encoder0Pos = max(encoder0Pos, 0);
    }
  }
  // Look for a high-to-low on channel B
  else { 
    // check channel B for encoder direction  
    if (digitalRead(encoder0PinA) == LOW) {   
      encoder0Pos++;          // CW
      encoder0Pos = min(encoder0Pos, 127);  
    } 
    else {
      encoder0Pos--;          // CCW
      encoder0Pos = max(encoder0Pos, 0);
    }
  }
}


//interrupt code to read LEFT linear encoder

void doEncoder1A(){

  // look for a low-to-high on channel A
  if (digitalRead(encoder1PinA) == HIGH) { 
    // check channel B for encoder direction
    if (digitalRead(encoder1PinB) == LOW) {  
      encoder1Pos++;                         // CW
      encoder1Pos = min(encoder1Pos, 127);
    } 
    else {
      encoder1Pos--;                         // CCW
      encoder1Pos = max(encoder1Pos, 0);
    }
  }
  else   // must be a high-to-low edge on channel A                                       
  { 
    // check channel B for encoder direction 
    if (digitalRead(encoder1PinB) == HIGH) {   
      encoder1Pos++;          // CW
      encoder1Pos = min(encoder1Pos, 127);     
    } 
    else {
      encoder1Pos--;          // CCW
      encoder1Pos = max(encoder1Pos, 0); 
    }
  }
}

void doEncoder1B(){

  // look for a low-to-high on channel B
  if (digitalRead(encoder1PinB) == HIGH) {   
    // check channel A for encoder direction
    if (digitalRead(encoder1PinA) == HIGH) {  
      encoder1Pos++;         // CW
      encoder1Pos = min(encoder1Pos, 127);  
    } 
    else {
      encoder1Pos--;         // CCW
      encoder1Pos = max(encoder1Pos, 0);
    }
  }
  // Look for a high-to-low on channel B
  else { 
    // check channel B for encoder direction
    if (digitalRead(encoder1PinA) == LOW) {   
      encoder1Pos++;          // CW
      encoder1Pos = min(encoder1Pos, 127);  
    } 
    else {
      encoder1Pos--;          // CCW
      encoder1Pos = max(encoder1Pos, 0);
    }
  }
}

boolean pulse_flag = false;

//Timer2 overflow interrupt vector handler
ISR(TIMER2_OVF_vect) {

  if (start_flag == true) {     //send out the midi start and synch the LFO in a nice orderly manner
    phase = 0;                        //reset waveform on midi start
    Serial3.print(midi_start, BYTE);
    start_flag = false;
  }

  int led_out = PULSE_TABLE[phase>>8];   //blinkie LED on board 
  if (inhibit_LED == false)         //no blinkies while reading BPM use a timer in the loop to pulse the LED instead
  analogWrite (wave_led_pin, led_out);

  phase_tab = phase*12;                      //advance the table reading by 12 x, half of 24 midi ticks per waveform period to accomodate higher BPM's
  int midi_tick_out = MIDI_TICK_TABLE[phase_tab>>8];
  if (midi_tick_out == 0xff && pulse_flag == false && midi_clock_flag == true) {   //flag needed so we don't get multiple midi writes
    pulse_flag = true;
    Serial3.print(midi_clock, BYTE);          // send out 12 ticks per period 
  }
  if (midi_tick_out == 0x00 && pulse_flag == true)   //reset the flag
    pulse_flag = false;
    
    
  for(int i=0; i < 4; i++) {                   //output the four channels of waveforms
    if (wave_channel[i] != 0) {
      resistance = *(waveArr[i] + (phase>>8));  // pull out the waveshape by channel
      write_pot_a(i,resistance);
    }    
  }

  phase += phaseDelta;

  functArr[I](I);       // run one state machine once per interrupt
  I = I++;
  if (I > 3) {
    I = 0;
  }
  //Capture the current timer value. This is how much error we have
  //due to interrupt latency and the work in this function
  // put this at the end of a time sensitive function and it will correct the timer interrupt fire
  latency=TCNT2;

  //Reload the timer and correct for latency.  //Reload the timer and correct for latency.  //Reload the timer and correct for latency.
  TCNT2=latency+timerLoadValue; 
}




int main(void)
{
	init();

	setup();
    
	for (;;)
		loop();
        
	return 0;
}

